
#Requires AutoHotkey v2.0
#Include TextProcessor.ahk 

#Include FileTool.ahk
#Include SimLog.ahk 

; 处理CSV文件(v1.01)
class CSV_Pcr extends TextProcessor {

    ; 日志对象
    logger := Simlog()
    logger.enable := true ; 日志是否启用
    
    ; csv文件原文
    text := ""

    ; csv数据(二维数组)
    content := []

    ; 异常提示
    errTip := "#无数据#"

    ; ????
    special := [",", "`n", "`r"]

    ; 无效字符(逗号，回车，换行，引号)
    invalid := ',`r`n`"'

    ; 分割符
    separator := ","

    ; 行分割符
    lineSeparator := "`n"

    ; 读
    read(text := this.text) {
        
        ; 默认参数
        this.text := text

        ; 写日志
        this.logger.log(this.logger.nlch . "尝试读取数据...")

        ; 声明局部变量
        local rows := [], cells := []

        ; 声明局部变量
        local s := 1, e := 1, len := StrLen(this.text)

        ; 放行(此参数为true,知道遇到了另外一个引号,不再判断其他字符)
        local proceed := false

        ; 换行(此参数为true,表示这条数据是一行的最后一条数据)
        local enter := false

        loop parse Trim(this.text) {

            if (A_LoopField == '`"') { ; 引号

                if (proceed) {
                    e := A_Index
                } else {
                    s := A_Index
                    e := A_Index
                }
                proceed := !proceed ; 取反

            }

            if (proceed) {
                continue
            }

            if (A_LoopField == this.separator) { ; 分割符
                e := A_Index
            }

            if (A_LoopField == this.lineSeparator) { ; 换行分割符
                e := A_Index

                ; 标记这条数据是本行的最后一条数据
                enter := true 
            }

            if (e != s) { ; 如果开始坐标与结束坐标不同，说明到了一条数据结束的位置

                 ; 切割字符串
                t := e - s
                cell := SubStr(this.text, s, (e - s))
                
                cell := Trim(cell, this.invalid) ; 去掉多余(无效)字符

                if(cell == ""){
                    s := e ; 跳过(s等于e,继续循环)
                    continue
                }

                cells.Push(cell)
                this.logger.log("[" . A_Index . "][" . s . "," . e . "] '" . cell . "'")
                s := e ; 跳过(s等于e,继续循环)

                ; 按行归档
                if(enter){
                    enter := false
                    rows.Push(cells) ; 存入数组
                    cells := [] ; 置零
                }
            }
            
        }
        
        ; 如果最后一行有数据
        if(cells.Length != 0){
            rows.Push(cells) ; 存入最后一行数据
        }

        this.content := rows
        return this.content
    }

    ; 写
    write(content := this.content) {

        this.content := content

        ; 声明局部变量
        local table := this.content, rows := "", row, cell

        ; 遍历每一行
        for row in table {
            
            ; 遍历每一个元素
            for cellIndex, cell in row {

                cell := this._formatCell(cell)
                if (cellIndex == row.length) {
                    rows .= cell ; 一行的最后一个元素不加逗号(分割符)
                    break
                }
                rows .= cell . "," ; 加逗号(分割符)

            }
            rows .= "`n" ; 加换行
        }

        return rows
    }


    ; 获取某个单元格的数据(row 第几行 col 第几列)
    getCell(row, col) {

        if (!this.content) { ; 不存在
            return this.errTip
        }

        if (this.content.length == 0) {
            return this.errTip ; 无数据
        }
        
        ; 尝试捕获异常(数组下标越界)
        try {
            testText := this.content[row][col]
        } catch Error as e{
            this.logger.log(Format("查询单元格[{1},{2}] : '{3}'", row, col, this.errTip))
            return this.errTip
        }

        this.logger.log(Format("查询单元格[{1},{2}] : '{3}'", row, col, this.content[row][col]))
        
        return this.content[row][col]
    }

    ; 格式化单元格
    _formatCell(cell) {

        if (!InStr(cell, ",") && !InStr(cell, "`"")) {
            return cell
        }

        ; 如果单元格包含双引号，则替换为两个双引号
        cell := StrReplace(cell, "`"", "`"`"")

        ; 为特殊字符加上引号
        cell := this._addQuote(cell)

        return cell
    }

    ; 加引号
    _addQuote(cell) {
        cell := Format('`"{1}`"',cell) 
        return cell
    }

}


